gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdows/ringbasewnd.cpp

    /**********************************************************************
//
//
//        ##########                          ######  #########   # ######    #
//      #############                      ########### ######### #########  ###
//     ######## # ###  ##                 ############# ##    ## #####  # ####
//     ####  ##    ## ###                 ###     ### # #      #####   #####
//          #     ###  #            #     ##       ##  ##      ##     ###
//         ## ###### ##      ##  ####    ####          #       #     ##
//       #########  ###  ## ### #######   ######      ##      ##    ###
//      ######      ##  ######  ##  ##       ####     #      ##     ####
//     #######     ##   ###### ##  ###          ##   ##     ###    ######
//     #########   ##  ###### ## ######         ### ##    ###      #  #####
//    ##    ###### ####### ### #### ##  ## #######  ########      ##    ####
//    ##      #### ###  #  ### ### ##  ##########   ######       ##      ####
//   ##         ##                ##   #########    ####         #         ##
//               #              ###
//                              ##
//                             ###
//                             ##
//
//
//							临风程序界面类库 ringdows.lib
//作者:临风
//
//版本:1.0
//
//声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到
//		  你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在
//		  修改的同时给作者一份同样的副本。
//		  本类库不得用于任何商业用途,如确实需要,请与作者联系。
//
//e-mail:ringphone@sina.com
//
//原文件名:ringbasewnd.cpp
//
//本文件说明:窗口类实现代码,本文件包括:
//					RingBaseWnd类   -- 基类,所有窗口类从该类派生
//
**********************************************************************/

#define MAKE_SELF_LIB
#include "ringdows.h"

//根据窗口句柄得到窗口类对象指针,所有利用界面库创建的窗口
//均有此特性以支持该函数
RingBaseWnd* GetWindowPtr(HWND hWnd)
{
	return (RingBaseWnd*)SendMessage(hWnd,MYWM_GETCLASS,0xCCCCDDDD,GetCurrentProcessId());
}

//检测窗口对象是否有效
BOOL IsWindowPtr(RingBaseWnd* obj)
{
	if(obj == NULL)
		return FALSE;

	try
	{
		return (obj == GetWindowPtr(obj->Handle()));
	}
	catch(...)
	{
		return FALSE;
	}
	return FALSE;
}

//for dockbar only
BOOL IsVert(int state)
{
	return (state > TBS_FLAG_DOCKBOTTOM && state <= TBS_FLAG_DOCKRIGHT);
}

BOOL IsHorz(int state)
{
	return (state <= TBS_FLAG_DOCKBOTTOM || state == TBS_FLAG_NONE);
}

BOOL IsFloat(int state)
{
	return (state == TBS_FLAG_FLY);
}

void InitIPControl()
{
	InitCommonCtl32(ICC_INTERNET_CLASSES);
}

void InitBarControl()
{
	InitCommonCtl32(ICC_BAR_CLASSES);
}

void InitCommonCtl32(DWORD dwICC)
{
	INITCOMMONCONTROLSEX cx = {sizeof(INITCOMMONCONTROLSEX),dwICC};
	InitCommonControlsEx(&cx);
}

//RINGSYSCOLOR RingBaseWnd::m_crSys;
//RingdowList RingWnd::m_windowList;
//RingMsgs* RingWnd::m_msgs = NULL;

WNDPROC CreateThunk(RingBaseWnd* w,WNDPROC thunkProc);

//该结构必须以字节对齐
#pragma pack(push,1)
struct RingThunk {
	BYTE				Call;
	int				Offset;
	WNDPROC			Proc;
	BYTE				Code[5];
	RingBaseWnd*   Window;
	BYTE				Jmp;
	BYTE				ECX;	
};
#pragma pack(pop)

/******************************************************
//
//初始化m_thunk
//		WNDCLASSDE的lpfnWndProc成员需要WNDPROC的函数指针,但是
//		类成员函数除非是静态的,否则无法转换到WNDPROC,不过我们
//		可以利用WNDPROC类型的成员数据,在m_thunk做手脚,让其指
//		向一小段汇编代码,把窗口对象this指针记录下来。
//		本来想让该段代码转向到静态stdProc回调函数的同时
//		把窗口对象的this指针放到eax,这样在stdProc里就可以从
//		eax取回对象指针,定位到RingdowProc了,但是VC的DEBUG编译
//		会在函数调用时(取得eax值之前)把eax赋值0xCCCCCCCC
//		:(,于是采用将this指针替换到HWND的方法,因此请注意:
//		窗口消息处理函数的HWND参数是对象指针!!!,而该HWND已在
//		第一次调用thunk之前记录下来,可以用窗口对象的Handle()
//		得到。
//
******************************************************/
#define OFFSET_OF(st_name,md_name)  (size_t)&(((st_name *)0)->md_name)
static const int g_Offset = OFFSET_OF(RingThunk,Code) - OFFSET_OF(RingThunk,Proc);

WNDPROC CreateThunk(RingBaseWnd* w, WNDPROC thunkProc)
{
	RingThunk*  thunk = (RingThunk*)New(sizeof(RingThunk));
	
	///////////////////////////////////////////////
	//
	//系统调用m_thunk时的堆栈:
	//ret HWND MSG WPARAM LPARAM
	//-------------------------------------------
	//栈顶											 栈底
	///////////////////////////////////////////////

	//call g_Offset
	//调用code[0],call执行时会把下一条指令压栈,即把Proc压栈
	thunk->Call = 0xE8;        // call [rel]32
	thunk->Offset = g_Offset;  // 偏移量,跳过Proc到Code[0]
	thunk->Proc = thunkProc;
	
	//pop ecx,Proc已压栈,弹出Proc到ecx	
	thunk->Code[0] = 0x59;		//pop ecx
	
	//mov dword ptr [esp+0x4],w
	//Proc已弹出,栈顶是返回地址,紧接着就是HWND了。
	//[esp+0x4]就是HWND
	thunk->Code[1] = 0xC7;		//	mov
	thunk->Code[2] = 0x44;		//	dword ptr
	thunk->Code[3] = 0x24;		//	disp8[esp]
	thunk->Code[4] = 0x04;		//	+4
	thunk->Window = w;
	
	//偷梁换柱成功!跳转到Proc
	//jmp [ecx]
	thunk->Jmp = 0xFF;     // jmp [r/m]32
	thunk->ECX = 0x21;     // [ecx]
	
	return (WNDPROC)thunk;
}
/*
_RingSysColors::_RingSysColors()
{
	cr3DDKSHADOW = GetSysColor(COLOR_3DDKSHADOW);
	crBTNFACE = GetSysColor(COLOR_BTNFACE);
	cr3DLIGHT = GetSysColor(COLOR_3DLIGHT);
	cr3DSHADOW = GetSysColor(COLOR_3DSHADOW);
	crBTNTEXT = GetSysColor(COLOR_BTNTEXT);
	crGRAYTEXT = GetSysColor(COLOR_GRAYTEXT);
	crHIGHLIGHT = GetSysColor(COLOR_HIGHLIGHT);
	crHIGHLIGHTTEXT = GetSysColor(COLOR_HIGHLIGHTTEXT);
	crMENU = GetSysColor(COLOR_MENU);
	crMENUTEXT = GetSysColor(COLOR_MENUTEXT);
	crWINDOWTEXT = GetSysColor(COLOR_WINDOWTEXT);
}
*/
//ringFile rf = "debug.txt";
//char f[80];

//ATOM WINAPI RegRingdowClass(LPWNDCLASSEX lpwc)
BOOL WINAPI RegRingdowClass(LPWNDCLASSEX lpwc)
{
	WNDCLASSEX wndex;
	wndex.cbSize = sizeof(WNDCLASSEX);

	if(GetClassInfoEx(GetInstance(),lpwc->lpszClassName,&wndex))
		return TRUE;
	else
	{
		ATOM atom = RegisterClassEx(lpwc);
      if(!atom)
			atom = RegisterClass((LPWNDCLASS)lpwc->style);
		return (BOOL)atom;
	}

/*
	//原始版本,因为AddAtom后没有记录ATOM,
	//程序退出时无法DeleteAtom造成内存泄露。	
	ATOM atom = FindAtom(lpwc->lpszClassName);

	if(atom == NULL)
	{
      atom = RegisterClassEx(lpwc);
      if(!atom)
		   atom = RegisterClass((LPWNDCLASS)lpwc->style);

		if(atom)
			AddAtom(lpwc->lpszClassName);
	}
	return atom;
*/
}

//#ifdef _DEBUG
//RingdowList RingBaseWnd::m_RingdowList;
//void* RingBaseWnd::operator new(size_t size,char *file/*=__FILE__*/,int line/*=__LINE__*/)
//#else
void* RingBaseWnd::operator new(size_t size)
//#endif
{
	char *s = ::new char[size];
   if(s)
   {
		RingBaseWnd* temp = (RingBaseWnd*)s;
      temp->bNeedDestroy = 0x12345678;
//#ifdef _DEBUG
//		m_RingdowList.AddItem(temp,file,line);
//#endif
   }
   return s;
}

//#ifdef _DEBUG
//void RingBaseWnd::operator delete(void* w,char *file/*=__FILE__*/,int line/*=__LINE__*/)
//{
//	delete w;
//}
//#endif
/*
void RingBaseWnd::operator delete(void* w)
{
	if(w == NULL)
		return;

	//if(((RingBaseWnd*)w)->bNeedDestroy == 0x12345678)
	{	
//#ifdef _DEBUG
//		m_RingdowList.DelItem((RingBaseWnd*)w);
//#endif
		::delete (RingBaseWnd*)w;
	}
}
//*/
RingBaseWnd::RingBaseWnd()
{
	m_hWnd = NULL;
	m_thunk = NULL;
	m_DefProc = NULL;
	m_brush = NULL;
	m_bKillOnExit = FALSE;
	m_parent = this;
	//m_bKeyDown = FALSE;

	if(bNeedDestroy != 0x12345678)
		bNeedDestroy = 0;	
}

RingBaseWnd::~RingBaseWnd()
{
	if(bNeedDestroy == 0)
	{
		//非new产生的对象,有可能Attach一个窗口,在窗口关闭
		//前该对象就被销毁,需要Detach,把原窗口过程归还。		
		Detach();
	}
	bNeedDestroy = -1;
	m_hWnd = NULL;
	m_thunk = (WNDPROC)Del((RingThunk*)m_thunk);	
}

HWND RingBaseWnd::SetParent(HWND hParentWnd)
{
	return ::SetParent(m_hWnd,hParentWnd);	
}

COLORREF RingBaseWnd::GetBkColor(HDC hDC/*=NULL*/)
{
	if(m_hWnd)
	{
		COLORREF cr;

		if(hDC == NULL)
		{
			hDC = GetDC(m_hWnd);
			cr = ::GetBkColor(hDC);
			ReleaseDC(m_hWnd,hDC);
		}
		else
			cr = ::GetBkColor(hDC);
		return cr;
	}
	return CLR_INVALID;
}

HBRUSH RingBaseWnd::SetBkgColor(COLORREF crColor)
{
	if(m_brush)
		DeleteObject(m_brush);
	
	m_brush = CreateSolidBrush(crColor);
	SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)m_brush);
	return m_brush;
}

HBRUSH RingBaseWnd::SetBkgBitmap(HBITMAP hbm)
{	
	if(hbm)
	{
		if(m_brush)
			DeleteObject(m_brush);
		
		m_brush = CreatePatternBrush(hbm);
		SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)m_brush);
		return m_brush;
	}
	return NULL;
}

HBRUSH RingBaseWnd::SetBkgBitmap(UINT uId,HINSTANCE hInst)
{
	HBITMAP bmp = LoadBitmap(hInst,MAKEINTRESOURCE(uId));
	SetBkgBitmap(bmp);
	DeleteObject(bmp);
	return m_brush;
}

//窗口退出的最后一个消息
void RingBaseWnd::OnNcDestroy()
{
	try
	{
		if(m_brush)
			DeleteObject(m_brush);
	}
	catch(...)
	{
	}
	if(bNeedDestroy == 0x12345678 && m_bKillOnExit)
		delete this;	
}

WNDPROC RingBaseWnd::InitThunk()
{
	if(m_thunk == NULL)
		m_thunk = CreateThunk(this,stdProc);
	return m_thunk;
}

LRESULT CALLBACK WINAPI RingDialog::InitDlgProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{   
	if(uMsg == WM_INITDIALOG)
	{
		RingWnd *w = ((LPRINGWNDPARAM)lParam)->WndObj;
		
		if(w)
		{
			//把窗口消息处理函数设置为w->m_thunk,由thunk转向到stdProc
			w->SubClassWindow(hWnd);
			
			//防止再次进入本消息循环
			if(w->m_DefProc == InitDlgProc || w->m_DefProc == NULL)
				w->m_DefProc = DefaultDlgProc;
			return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);//((LPRINGWNDPARAM)lParam)->dwInitParam);
		}
	}
	return FALSE;
}

//打开/保存文件对话框HOOK对话框
LRESULT CALLBACK WINAPI RingOFNHookDialog::InitDlgProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
	if(uMsg == WM_INITDIALOG)
	{
		try
		{
			LPOPENFILENAME lpofn = (LPOPENFILENAME)lParam;
			RingOFNHookDialog *w = (RingOFNHookDialog*)lpofn->lCustData;
		
			if(w)
			{
				//把窗口消息处理函数设置为w->m_thunk,由thunk转向到stdProc
				w->SubClassWindow(hWnd);
				
				//防止再次进入本消息循环
				if(w->m_DefProc == InitDlgProc || w->m_DefProc == NULL)
					w->m_DefProc = DefaultDlgProc;

				LRESULT res = (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);//((LPRINGWNDPARAM)lParam)->dwInitParam);
				//子类化父窗口,如父窗口可改变尺寸,则系统默认动作为修改控件位置,
				//有可能会乱。对于HOOK对话框,系统默认动作为改变该对话框尺寸,将所有
				//控件挪到文件列表下方,用户拖动改变尺寸时改变该对话框尺寸,移动所有
				//控件。如果本对话框在响应CDN_INITDONE消息时还原为设计时尺寸并还原
				//控件位置,将对话框移动到文件列表右方,则拖动改变尺寸时系统判断
				//控件位置有误,不会移动控件,而本对话框无法知道父窗口尺寸已改变,
				//因此须子类化父窗口,在改变尺寸时发送WM_SIZE给本对话框。
				try
				{
					w->m_thunkParent = CreateThunk(w,OFNDlgProc);
					w->m_hWndParent = ::GetParent(hWnd);
					w->m_OFNProc = (WNDPROC)SetWindowLong(w->m_hWndParent,DWL_DLGPROC,
																		(LONG)w->m_thunkParent);
				}
				catch(...)
				{
				}
				return res;
			}
		}
		catch(...)
		{
		}
	}
	return FALSE;
}

LRESULT CALLBACK WINAPI RingOFNHookDialog::OFNDlgProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
	RingOFNHookDialog* w = (RingOFNHookDialog*)hWnd;
	
	if(uMsg == WM_SIZE)
	{
		LRESULT res = CallWindowProc(w->m_OFNProc,w->m_hWndParent,uMsg,wParam,lParam);
		::SendMessage(w->Handle(),WM_SIZE,0,0);
		return res;
	}
	return CallWindowProc(w->m_OFNProc,w->m_hWndParent,uMsg,wParam,lParam);
}

LRESULT CALLBACK WINAPI RingPropPage::InitPageProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{   
	if(uMsg == WM_INITDIALOG)
	{		
		RingPropPage *w = NULL;
		
		w = (RingPropPage*)((LPRINGWNDPARAM)((LPPROPSHEETPAGE)lParam)->lParam)->WndObj;
		
		char szTitle[80];
		GetWindowText(hWnd,szTitle,80);
		((LPPROPSHEETPAGE)lParam)->pszTitle = szTitle;

		if(w)
		{
			w->SubClassWindow(hWnd);
			RingBaseWnd* parent = w->Parent();
			if(parent->GetWindowType() == ITIS_PROPSHEET)
				parent->Attach(w->GetParent());
			
			if(w->m_DefProc == InitPageProc || w->m_DefProc == NULL)
				w->m_DefProc = DefaultDlgProc;
			return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,((LPRINGWNDPARAM)((LPPROPSHEETPAGE)lParam)->lParam)->dwInitParam);
		}
	}
	return FALSE;
}

LRESULT CALLBACK WINAPI RingBaseWnd::InitWndProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{   
	if(uMsg == WM_NCCREATE)
	{
		RingBaseWnd *w = NULL;
		w = (RingBaseWnd*)((LPRINGWNDPARAM)((LPCREATESTRUCT)lParam)->lpCreateParams)->WndObj;
		if(w)
		{
			w->SubClassWindow(hWnd);
			
			if(w->m_DefProc == InitWndProc || w->m_DefProc == NULL)
				w->m_DefProc = DefWindowProc;

			//((LPCREATESTRUCT)lParam)->lpCreateParams = 
			//	(LPVOID)((LPRINGWNDPARAM)((LPCREATESTRUCT)lParam)->lpCreateParams)->dwInitParam;

			return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);
		}
	}	
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

LRESULT CALLBACK WINAPI RingMDIChildWnd::InitChildProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
   if(uMsg == WM_NCCREATE)
	{
		MDICREATESTRUCT *ms = (MDICREATESTRUCT*)((LPCREATESTRUCT)lParam)->lpCreateParams;
		RingMDIChildWnd* w = (RingMDIChildWnd*)((LPRINGWNDPARAM)ms->lParam)->WndObj;
		if(w)
		{
			w->SubClassWindow(hWnd);
			
			if(w->m_DefProc == InitChildProc || w->m_DefProc == NULL)
				w->m_DefProc = DefMDIChildProc;
			
			ms->lParam = ((LPRINGWNDPARAM)((RingMDIChildWnd*)ms->lParam))->dwInitParam;
			//((LPCREATESTRUCT)lParam)->lpCreateParams = 
			//	(LPVOID)((LPRINGWNDPARAM)((RingMDIChildWnd*)ms->lParam))->dwInitParam;

			return (*(WNDPROC)(w->GetThunk()))(hWnd,uMsg,wParam,lParam);
		}
   }
   
   return DefMDIChildProc(hWnd,uMsg,wParam,lParam);
}

//本回调函数的HWND调用之前已由m_thunk替换为对象指针
LRESULT CALLBACK WINAPI RingBaseWnd::stdProc(HWND hWnd,UINT uMsg,UINT wParam,LONG lParam)
{
	RingBaseWnd* w = (RingBaseWnd*)hWnd;
	
	if(uMsg == MYWM_GETCLASS && wParam == 0xCCCCDDDD && (DWORD)lParam == GetCurrentProcessId())
	{
		//对话框,必须设置返回值
		if(w->GetWindowType() <= ITIS_DIALOG && w->GetWindowType() >= ITIS_PROPSHEET)
			SetWindowLong(w->Handle(),DWL_MSGRESULT,(LONG)w);
		return (LONG)w;
	}
	//else if(uMsg == WM_KEYDOWN)
	//	w->m_bKeyDown = TRUE;
	
	w->m_param.uMsg = uMsg;
	w->m_param.wParam = wParam;
	w->m_param.lParam = lParam;
	/*if(uMsg == WM_KEYUP && w->m_bKeyDown)
	{
		HWND hWnd = w->m_hWnd;

		w->m_bKeyDown = FALSE;		
		LRESULT res = w->RingdowProc(w->m_hWnd,w->m_param);
		if(::IsWindow(hWnd))		
			//发送WM_KEYPRESS消息
			::SendMessage(hWnd,WM_KEYPRESS,wParam,lParam);
		return res;
	}
	*/
	return w->RingdowProc(w->m_hWnd,w->m_param);	
}

LRESULT RingBaseWnd::RingdowProc(HWND hWnd,RINGPARAMS param)
{
	return DefaultProc(param);
}

LRESULT RingBaseWnd::CtlColorProc(HWND hWnd,RINGPARAMS& param)
{	
	switch(param.uMsg)
	{
		case WM_CTLCOLORBTN:
		case WM_CTLCOLOREDIT:
		case WM_CTLCOLORLISTBOX:
		case WM_CTLCOLORSCROLLBAR:
		case WM_CTLCOLORSTATIC:
		{
			RingBaseWnd* obj = GetWindowPtr((HWND)param.lParam);
			if(obj)
				return obj->OnBkColor(param.uMsg,param.hdc);
		}	
	}	
	return RM_NOTPROCESS;
}

//通知子窗口处理消息,如WM_SIZE等,子窗口可以跟随父窗口调整尺寸
void RingBaseWnd::NotifyChild(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	HWND hChildWnd = GetChild();
	RingBaseWnd* tmp;
	while(hChildWnd)
	{
		tmp = GetWindowPtr(hChildWnd);
		if(tmp)// && tmp->Parent() == this )//&& tmp->IsControls())
			tmp->OnParentNotify(hWnd,uMsg/* + MYWM_BASEEX*/,wParam,lParam);
		hChildWnd = GetNextChild(hChildWnd);
	}
}

BOOL RingBaseWnd::NotifyChildDrawItem(HWND hParentWnd,HWND hWnd,UINT uMsg,
												  WPARAM wParam,LPARAM lParam)
{
	RingBaseWnd* tmp = GetWindowPtr(hWnd);

	if(tmp && tmp->OnParentNotify(hParentWnd,uMsg,wParam,lParam))
		return TRUE;
	else
		return FALSE;
}

//子类化窗口过程
WNDPROC RingBaseWnd::SubClassWindow(HWND hWnd)
{
	if(!::IsWindow(hWnd))
		return NULL;

	m_hWnd = hWnd;
	m_DefProc = (WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(LONG)InitThunk());
	return m_DefProc;
}

BOOL RingBaseWnd::Attach(HWND hWnd)
{
	if(m_hWnd && m_DefProc)	//已捆绑到窗口
	{
		if(m_hWnd != hWnd)	//要捆绑到另外的窗口
		{
			RingBaseWnd* w = GetWindowPtr(hWnd);
			if(w != NULL)		//目标窗口已被捆绑,不可替换
				return FALSE;
			else
				if(!Detach())	//脱离捆绑当前窗口
					return FALSE;
		}
		else
			return TRUE;
	}
	
	m_DefProc = SubClassWindow(hWnd);
	if(m_DefProc)
	{
		m_hWnd = hWnd;
		if(m_parent == this)
			SetParentObj(GetParent());
		return TRUE;
	}
	else
	{
		m_hWnd = NULL;
		return FALSE;
	}
}

BOOL RingBaseWnd::Detach()
{
	if(m_hWnd && m_DefProc && IsWindow())
	{
		BOOL bOK;
		if(m_windowType <= ITIS_DIALOG && m_windowType >= ITIS_PROPSHEET)
			bOK = SetWindowLong(m_hWnd,DWL_DLGPROC,(LONG)m_DefProc);
		else
			bOK = SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)m_DefProc);
		if(bOK)
		{
			m_DefProc = NULL;
			m_hWnd = NULL;
			return TRUE;
		}
		else
			return FALSE;
	}
	else
	{
		m_DefProc = NULL;
		m_hWnd = NULL;
		return TRUE;
	}	
}
/*
RingOwnerDrawer* RingBaseWnd::SetItemOwnerDraw(RingOwnerDrawer* drawer)
{
	return RingControls::SetDrawer(drawer);
}
*/
void RingBaseWnd::SetTitle(LPCTSTR szTitle)
{
   if(szTitle)
		SetWindowText(m_hWnd,szTitle);
}

void RingBaseWnd::SetCursor(HCURSOR hCur)
{
   if(hCur == NULL)
		SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
	else
		::SetCursor(hCur);
}

BOOL RingBaseWnd::SetPos(int x,int y,int width,int height,HWND hPos,UINT uFlags)
{
	if(width==-999 && height == -999)
		uFlags |= SWP_NOSIZE;

	return SetWindowPos(m_hWnd,hPos,x,y,width,height,uFlags);
}

BOOL RingBaseWnd::CenterWindow(BOOL bWithParent)
{
   RECT    rcChild, rcParent;
   int     cxChild, cyChild, cxParent, cyParent;
   int     cxScreen, cyScreen, xNew, yNew;
   HDC     hdc;
   HWND 	  hwndParent;

   GetWindowRect(m_hWnd,&rcChild);
   cxChild = rcChild.right - rcChild.left;
   cyChild = rcChild.bottom - rcChild.top;

   if(bWithParent && m_parent != this)
   	hwndParent = m_parent->m_hWnd;
   else
     	hwndParent = GetDesktopWindow();

   GetWindowRect(hwndParent,&rcParent);
   cxParent = rcParent.right - rcParent.left;
   cyParent = rcParent.bottom - rcParent.top;

   hdc = GetDC(m_hWnd);
   cxScreen = GetDeviceCaps(hdc,HORZRES);
   cyScreen = GetDeviceCaps(hdc,VERTRES);
   ReleaseDC(m_hWnd,hdc);

   xNew = rcParent.left + ((cxParent - cxChild) / 2);
   if(xNew < 0)
   	xNew = 0;
   else if((xNew + cxChild) > cxScreen)
	   xNew = cxScreen - cxChild;

   yNew = rcParent.top  + ((cyParent - cyChild) / 2);
   if(yNew < 0)
	   yNew = 0;
   else if((yNew + cyChild) > cyScreen)
      yNew = cyScreen - cyChild;

	return SetPos(xNew,yNew,0,0,NULL,SWP_NOSIZE | SWP_NOZORDER);
}

void RingBaseWnd::SetExStyle(DWORD dwExStyle)
{
  	SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle);
}

void RingBaseWnd::SetStyle(DWORD dwStyle)
{
  	SetWindowLong(m_hWnd,GWL_STYLE,dwStyle);
}

void RingBaseWnd::SetParentObj(RingBaseWnd* parent)
{
	if(parent)
   	m_parent = parent;
   else
   	m_parent = this;
}

BOOL RingBaseWnd::SetParentObj(HWND hParentWnd)
{
	RingBaseWnd* tmp = GetWindowPtr(hParentWnd);
	if(tmp)
	{
		m_parent = tmp;
		return TRUE;
	}
   else
	{
		m_parent = this;
		return FALSE;
	}
}

void RingBaseWnd::ReplaceStyle(DWORD dwsRemove,DWORD dwsReplace)
{
	DWORD style = GetWindowLong(m_hWnd,GWL_STYLE);
   style &= ~dwsRemove;
   style |= dwsReplace;
   SetWindowLong(m_hWnd,GWL_STYLE,style);
}

HWND RingBaseWnd::CreateEx(LPCTSTR szTitle,LPCTSTR szClass,DWORD dwStyle,
									DWORD dwExStyle,HWND hParentWnd/*=NULL*/,HMENU hMenu,
									int x,int y,int width,int height,LPARAM lParam/*=0*/)
{
	if(IsWindow())
		return m_hWnd;

	if(hParentWnd == NULL)
		hParentWnd = m_parent->Handle();
	else
		SetParentObj(GetWindowPtr(hParentWnd));

	RINGWNDPARAM wndParam = {(RingWnd*)this,lParam};

	CreateWindowEx(
				  		dwExStyle,
                  szClass,
                  szTitle,
                  dwStyle,
                  x,
                  y,
                  width,
                  height,
                  hParentWnd,
                  hMenu,
                  GetInstance(),
                  &wndParam
                  );
	//m_hWnd已在InitProc中记录
   return m_hWnd;
}

BOOL RingBaseWnd::Popup(RingBaseWnd* obj,LPCTSTR lpDlgOrTitle,LPARAM lParamOrClass,DWORD dwStyle,DWORD dwExStyle/* = 0*/)
{
   if(obj)
   {
		if(::IsWindow(obj->Handle()))
		{
			SetActiveWindow(obj->Handle());
			return TRUE;
			//SetForegroundWindow(obj->Handle());
		}
		else
		{
			if(obj->GetWindowType() == ITIS_DIALOG)
			{
				obj->SetParentObj(this);
				return ((RingDialog*)obj)->DoModal(lpDlgOrTitle,lParamOrClass);
			}
			else
			{
				obj->SetAutoDelete();
				return (BOOL)((RingWnd*)obj)->Create(lpDlgOrTitle,(LPCTSTR)lParamOrClass,dwStyle,dwExStyle);
			}
		}
	}
   return FALSE;
}

RingControls* RingBaseWnd::InsertItem(RingControls* item,DWORD dwStyle/*=0*/,int left/*=0*/,int top/*=0*/,int width/*=0*/,int height/*=0*/)
{
	if(item)
   {
      RingBaseWnd* w = item;
		w->SetParentObj(this);
   	
		if(item->Handle() == NULL)
			item->Create(dwStyle,0,NULL,item->GetId(),left,top,width,height);
		else
		{
			if(width == 0)
				width = item->Width();
			if(height)
				height = item->Height();

			item->SetParent(m_hWnd);
			item->SetPos(left,top,width,height);
		}
   }
   return item;
}

int RingBaseWnd::ClientWidth()
{
	RECT rc;
	GetClientRect(&rc);
	return rc.right - rc.left;
}

int RingBaseWnd::ClientHeight()
{
	RECT rc;
	GetClientRect(&rc);
	return rc.bottom - rc.top;
}

//得到窗口坐标(相对于父窗口,无父窗口则为屏幕坐标)
BOOL RingBaseWnd::GetRect(LPRECT lprc)
{
	if(lprc)
	{
		if(GetWindowRect(m_hWnd,lprc))
		{
			if(m_parent && m_parent != this)
			{
				ScreenToClient(m_parent->Handle(),(LPPOINT)lprc);
				ScreenToClient(m_parent->Handle(),(LPPOINT)lprc+1);
			}
			return TRUE;
		}
	}
	return FALSE;
}

//lprcPos坐标为相对于父窗口,即接受停靠的窗口
RingDockBar* RingBaseWnd::EnableDock(LPCTSTR szTitle,
										UINT uDockStyle/* = TBS_EX_DOCKABLE*/,
										UINT uDockFlag/* = TBS_FLAG_DOCKTOP*/,
										LPRECT lprcPos/* = NULL*/)
{
	if(!IsWindow() || !IsChild(m_parent->Handle(),m_hWnd))
		return NULL;
	
	if(!m_parent->IsControls() && m_parent->IsWindow())
	{
		UINT flag = uDockFlag;
		if(uDockFlag == TBS_FLAG_FLY)		//浮动,必须先创建一个DockSite
			flag = TBS_FLAG_DOCKTOP;
		
		RingDockSite* pSite = ((RingWnd*)m_parent)->CreateDockSite(flag);
		if(pSite)
			return pSite->AddBar(this,szTitle,uDockStyle,uDockFlag,lprcPos);
	}
	return NULL;
}

RingDockBar* RingBaseWnd::EnableDockSize(LPCTSTR szTitle,int nWidth,int nHeight,
											UINT uDockFlag/* = TBS_FLAG_DOCKTOP*/,
											UINT uDockStyle/* = TBS_EX_DOCKABLE*/)
{
	if(!IsWindow() || !IsChild(m_parent->Handle(),m_hWnd))
		return NULL;
	
	if(!m_parent->IsControls() && m_parent->IsWindow())
	{
		UINT flag = uDockFlag;
		if(uDockFlag == TBS_FLAG_FLY)		//浮动,必须先创建一个DockSite
			flag = TBS_FLAG_DOCKTOP;
		
		RingDockSite* pSite = ((RingWnd*)m_parent)->CreateDockSite(flag);
		if(pSite)
		{
			SetPos(0,0,nWidth,nHeight,NULL,SWP_NOMOVE);
			return pSite->AddBar(this,szTitle,uDockStyle,uDockFlag,NULL,TRUE);
		}
	}
	return NULL;
}

RingDockBar* RingBaseWnd::GetDockBar()
{
	//DockBar的父窗口对象(m_parent)与父窗口(是DockSite)不是同一个,
	//因此必须用以下方法得到真正的父窗口对象(DockSite或FlyBar)
	RingBaseWnd* wnd = GetWindowPtr(GetParent());
	RingDockBar* bar = NULL;

	if(wnd)
	{
		if(wnd->GetWindowType() == ITIS_DOCKSITE)
			bar = ((RingDockSite*)wnd)->GetDockBar(this);
		else if(wnd->GetWindowType() == ITIS_FLYBAR)
			bar = ((RingFlyBar*)wnd)->GetDockBar();
	}
	return bar;
}

void RingBaseWnd::DisableDock()
{
	RingBaseWnd* wnd = GetWindowPtr(GetParent());
	
	if(wnd)
	{
		if(wnd->GetWindowType() == ITIS_FLYBAR)
		{
			RingDockBar* bar = ((RingFlyBar*)wnd)->GetDockBar();
			wnd = bar->GetDockSite();
		}
		if(wnd->GetWindowType() == ITIS_DOCKSITE)
			((RingDockSite*)wnd)->ReleaseDockBar(this);
	}
}

int RingBaseWnd::GetDockState()
{
	RingDockBar* bar = GetDockBar();
	if(bar)
		return bar->GetState();
	else
		return -1;
}

//////////////////////////////////////
//
//lprcPos:相对于父窗口的坐标
//
//////////////////////////////////////
BOOL RingBaseWnd::DockTo(UINT uDockPos,LPRECT lprcPos/* = NULL*/)
{
	RingDockBar* bar = GetDockBar();
	if(bar)
		bar->Dockto(uDockPos,lprcPos);

	return (BOOL)bar;
}

int RingBaseWnd::DockBack()
{
	RingDockBar* bar = GetDockBar();
	if(bar)
		return bar->DockBack();
	else
		return -1;
}

HDWP RingBaseWnd::DefDeferWindowPos(HDWP hdwp,int x,int y,int width,int height,UINT uAppendFlag)
{
	return DeferWindowPos(hdwp,m_hWnd,0,x,y,width,height,
		SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|uAppendFlag);
}

char *
DecodeMessage(UINT msg)
{
    switch (msg)
    {
        case WM_NULL:               return("WM_NULL");
        case WM_CREATE:             return("WM_CREATE");
        case WM_DESTROY:            return("WM_DESTROY");
        case WM_MOVE:               return("WM_MOVE");
        case WM_SIZE:               return("WM_SIZE");
        case WM_ACTIVATE:           return("WM_ACTIVATE");
        case WM_SETFOCUS:           return("WM_SETFOCUS");
        case WM_KILLFOCUS:          return("WM_KILLFOCUS");
        case WM_ENABLE:             return("WM_ENABLE");
        case WM_SETREDRAW:          return("WM_SETREDRAW");
        case WM_SETTEXT:            return("WM_SETTEXT");
        case WM_GETTEXT:            return("WM_GETTEXT");
        case WM_GETTEXTLENGTH:      return("WM_GETTEXTLENGTH");
        case WM_PAINT:              return("WM_PAINT");
        case WM_CLOSE:              return("WM_CLOSE");
        case WM_QUERYENDSESSION:    return("WM_QUERYENDSESSION");
        case WM_QUERYOPEN:          return("WM_QUERYOPEN");
        case WM_ENDSESSION:         return("WM_ENDSESSION");
        case WM_QUIT:               return("WM_QUIT");
        case WM_ERASEBKGND:         return("WM_ERASEBKGND");
        case WM_SYSCOLORCHANGE:     return("WM_SYSCOLORCHANGE");
        case WM_SHOWWINDOW:         return("WM_SHOWWINDOW");
        case WM_WININICHANGE:       return("WM_WININICHANGE");
        case WM_DEVMODECHANGE:      return("WM_DEVMODECHANGE");
        case WM_ACTIVATEAPP:        return("WM_ACTIVATEAPP");
        case WM_FONTCHANGE:         return("WM_FONTCHANGE");
        case WM_TIMECHANGE:         return("WM_TIMECHANGE");
        case WM_CANCELMODE:         return("WM_CANCELMODE");
        case WM_SETCURSOR:          return("WM_SETCURSOR");
        case WM_MOUSEACTIVATE:      return("WM_MOUSEACTIVATE");
        case WM_CHILDACTIVATE:      return("WM_CHILDACTIVATE");
        case WM_QUEUESYNC:          return("WM_QUEUESYNC");
        case WM_GETMINMAXINFO:      return("WM_GETMINMAXINFO");
        case WM_PAINTICON:          return("WM_PAINTICON");
        case WM_ICONERASEBKGND:     return("WM_ICONERASEBKGND");
        case WM_NEXTDLGCTL:         return("WM_NEXTDLGCTL");
        case WM_SPOOLERSTATUS:      return("WM_SPOOLERSTATUS");
        case WM_DRAWITEM:           return("WM_DRAWITEM");
        case WM_MEASUREITEM:        return("WM_MEASUREITEM");
        case WM_DELETEITEM:         return("WM_DELETEITEM");
        case WM_VKEYTOITEM:         return("WM_VKEYTOITEM");
        case WM_CHARTOITEM:         return("WM_CHARTOITEM");
        case WM_SETFONT:            return("WM_SETFONT");
        case WM_GETFONT:            return("WM_GETFONT");
        case WM_SETHOTKEY:          return("WM_SETHOTKEY");
        case WM_GETHOTKEY:          return("WM_GETHOTKEY");
        case WM_QUERYDRAGICON:      return("WM_QUERYDRAGICON");
        case WM_COMPAREITEM:        return("WM_COMPAREITEM");
        case WM_COMPACTING:         return("WM_COMPACTING");
        case WM_COMMNOTIFY:         return("WM_COMMNOTIFY");
        case WM_WINDOWPOSCHANGING:  return("WM_WINDOWPOSCHANGING");
        case WM_WINDOWPOSCHANGED:   return("WM_WINDOWPOSCHANGED");
        case WM_POWER:              return("WM_POWER");
        case WM_COPYDATA:           return("WM_COPYDATA");
        case WM_CANCELJOURNAL:      return("WM_CANCELJOURNAL");
        case WM_NOTIFY:             return("WM_NOTIFY");
        case WM_INPUTLANGCHANGEREQUEST: return("WM_INPUTLANGCHANGEREQUEST");
        case WM_INPUTLANGCHANGE:    return("WM_INPUTLANGCHANGE");
        case WM_TCARD:              return("WM_TCARD");
        case WM_HELP:               return("WM_HELP");
        case WM_USERCHANGED:        return("WM_USERCHANGED");
        case WM_NOTIFYFORMAT:       return("WM_NOTIFYFORMAT");
        case WM_CONTEXTMENU:        return("WM_CONTEXTMENU");
        case WM_STYLECHANGING:      return("WM_STYLECHANGING");
        case WM_STYLECHANGED:       return("WM_STYLECHANGED");
        case WM_DISPLAYCHANGE:      return("WM_DISPLAYCHANGE");
        case WM_GETICON:            return("WM_GETICON");
        case WM_SETICON:            return("WM_SETICON");
        case WM_NCCREATE:           return("WM_NCCREATE");
        case WM_NCDESTROY:          return("WM_NCDESTROY");
        case WM_NCCALCSIZE:         return("WM_NCCALCSIZE");
        case WM_NCHITTEST:          return("WM_NCHITTEST");
        case WM_NCPAINT:            return("WM_NCPAINT");
        case WM_NCACTIVATE:         return("WM_NCACTIVATE");
        case WM_GETDLGCODE:         return("WM_GETDLGCODE");
        case WM_SYNCPAINT:          return("WM_SYNCPAINT");
        case WM_NCMOUSEMOVE:        return("WM_NCMOUSEMOVE");
        case WM_NCLBUTTONDOWN:      return("WM_NCLBUTTONDOWN");
        case WM_NCLBUTTONUP:        return("WM_NCLBUTTONUP");
        case WM_NCLBUTTONDBLCLK:    return("WM_NCLBUTTONDBLCLK");
        case WM_NCRBUTTONDOWN:      return("WM_NCRBUTTONDOWN");
        case WM_NCRBUTTONUP:        return("WM_NCRBUTTONUP");
        case WM_NCRBUTTONDBLCLK:    return("WM_NCRBUTTONDBLCLK");
        case WM_NCMBUTTONDOWN:      return("WM_NCMBUTTONDOWN");
        case WM_NCMBUTTONUP:        return("WM_NCMBUTTONUP");
        case WM_NCMBUTTONDBLCLK:    return("WM_NCMBUTTONDBLCLK");
        case WM_KEYDOWN:            return("WM_KEYDOWN");
        case WM_KEYUP:              return("WM_KEYUP");
        case WM_CHAR:               return("WM_CHAR");
        case WM_DEADCHAR:           return("WM_DEADCHAR");
        case WM_SYSKEYDOWN:         return("WM_SYSKEYDOWN");
        case WM_SYSKEYUP:           return("WM_SYSKEYUP");
        case WM_SYSCHAR:            return("WM_SYSCHAR");
        case WM_SYSDEADCHAR:        return("WM_SYSDEADCHAR");
        case WM_IME_STARTCOMPOSITION:   return("WM_IME_STARTCOMPOSITION");
        case WM_IME_ENDCOMPOSITION: return("WM_IME_ENDCOMPOSITION");
        case WM_IME_COMPOSITION:    return("WM_IME_COMPOSITION");
        case WM_INITDIALOG:         return("WM_INITDIALOG");
        case WM_COMMAND:            return("WM_COMMAND");
        case WM_SYSCOMMAND:         return("WM_SYSCOMMAND");
        case WM_TIMER:              return("WM_TIMER");
        case WM_HSCROLL:            return("WM_HSCROLL");
        case WM_VSCROLL:            return("WM_VSCROLL");
        case WM_INITMENU:           return("WM_INITMENU");
        case WM_INITMENUPOPUP:      return("WM_INITMENUPOPUP");
        case WM_MENUSELECT:         return("WM_MENUSELECT");
        case WM_MENUCHAR:           return("WM_MENUCHAR");
        case WM_ENTERIDLE:          return("WM_ENTERIDLE");
        case WM_CTLCOLORMSGBOX:     return("WM_CTLCOLORMSGBOX");
        case WM_CTLCOLOREDIT:       return("WM_CTLCOLOREDIT");
        case WM_CTLCOLORLISTBOX:    return("WM_CTLCOLORLISTBOX");
        case WM_CTLCOLORBTN:        return("WM_CTLCOLORBTN");
        case WM_CTLCOLORDLG:        return("WM_CTLCOLORDLG");
        case WM_CTLCOLORSCROLLBAR:  return("WM_CTLCOLORSCROLLBAR");
        case WM_CTLCOLORSTATIC:     return("WM_CTLCOLORSTATIC");
        case WM_MOUSEMOVE:          return("WM_MOUSEMOVE");
        case WM_LBUTTONDOWN:        return("WM_LBUTTONDOWN");
        case WM_LBUTTONUP:          return("WM_LBUTTONUP");
        case WM_LBUTTONDBLCLK:      return("WM_LBUTTONDBLCLK");
        case WM_RBUTTONDOWN:        return("WM_RBUTTONDOWN");
        case WM_RBUTTONUP:          return("WM_RBUTTONUP");
        case WM_RBUTTONDBLCLK:      return("WM_RBUTTONDBLCLK");
        case WM_MBUTTONDOWN:        return("WM_MBUTTONDOWN");
        case WM_MBUTTONUP:          return("WM_MBUTTONUP");
        case WM_MBUTTONDBLCLK:      return("WM_MBUTTONDBLCLK");
        case WM_MOUSEWHEEL:         return("WM_MOUSEWHEEL");
        case WM_PARENTNOTIFY:       return("WM_PARENTNOTIFY");
        case WM_ENTERMENULOOP:      return("WM_ENTERMENULOOP");
        case WM_EXITMENULOOP:       return("WM_EXITMENULOOP");
        case WM_NEXTMENU:           return("WM_NEXTMENU");
        case WM_SIZING:             return("WM_SIZING");
        case WM_CAPTURECHANGED:     return("WM_CAPTURECHANGED");
        case WM_MOVING:             return("WM_MOVING");
        case WM_POWERBROADCAST:     return("WM_POWERBROADCAST");
        case WM_DEVICECHANGE:       return("WM_DEVICECHANGE");
        case WM_MDICREATE:          return("WM_MDICREATE");
        case WM_MDIDESTROY:         return("WM_MDIDESTROY");
        case WM_MDIACTIVATE:        return("WM_MDIACTIVATE");
        case WM_MDIRESTORE:         return("WM_MDIRESTORE");
        case WM_MDINEXT:            return("WM_MDINEXT");
        case WM_MDIMAXIMIZE:        return("WM_MDIMAXIMIZE");
        case WM_MDITILE:            return("WM_MDITILE");
        case WM_MDICASCADE:         return("WM_MDICASCADE");
        case WM_MDIICONARRANGE:     return("WM_MDIICONARRANGE");
        case WM_MDIGETACTIVE:       return("WM_MDIGETACTIVE");
        case WM_MDISETMENU:         return("WM_MDISETMENU");
        case WM_ENTERSIZEMOVE:      return("WM_ENTERSIZEMOVE");
        case WM_EXITSIZEMOVE:       return("WM_EXITSIZEMOVE");
        case WM_DROPFILES:          return("WM_DROPFILES");
        case WM_MDIREFRESHMENU:     return("WM_MDIREFRESHMENU");
        case WM_IME_SETCONTEXT:     return("WM_IME_SETCONTEXT");
        case WM_IME_NOTIFY:         return("WM_IME_NOTIFY");
        case WM_IME_CONTROL:        return("WM_IME_CONTROL");
        case WM_IME_COMPOSITIONFULL:    return("WM_IME_COMPOSITIONFULL");
        case WM_IME_SELECT:         return("WM_IME_SELECT");
        case WM_IME_CHAR:           return("WM_IME_CHAR");
        case WM_IME_KEYDOWN:        return("WM_IME_KEYDOWN");
        case WM_IME_KEYUP:          return("WM_IME_KEYUP");
        case WM_MOUSEHOVER:         return("WM_MOUSEHOVER");
        case WM_MOUSELEAVE:         return("WM_MOUSELEAVE");
        case WM_CUT:                return("WM_CUT");
        case WM_COPY:               return("WM_COPY");
        case WM_PASTE:              return("WM_PASTE");
        case WM_CLEAR:              return("WM_CLEAR");
        case WM_UNDO:               return("WM_UNDO");
        case WM_RENDERFORMAT:       return("WM_RENDERFORMAT");
        case WM_RENDERALLFORMATS:   return("WM_RENDERALLFORMATS");
        case WM_DESTROYCLIPBOARD:   return("WM_DESTROYCLIPBOARD");
        case WM_DRAWCLIPBOARD:      return("WM_DRAWCLIPBOARD");
        case WM_PAINTCLIPBOARD:     return("WM_PAINTCLIPBOARD");
        case WM_VSCROLLCLIPBOARD:   return("WM_VSCROLLCLIPBOARD");
        case WM_SIZECLIPBOARD:      return("WM_SIZECLIPBOARD");
        case WM_ASKCBFORMATNAME:    return("WM_ASKCBFORMATNAME");
        case WM_CHANGECBCHAIN:      return("WM_CHANGECBCHAIN");
        case WM_HSCROLLCLIPBOARD:   return("WM_HSCROLLCLIPBOARD");
        case WM_QUERYNEWPALETTE:    return("WM_QUERYNEWPALETTE");
        case WM_PALETTEISCHANGING:  return("WM_PALETTEISCHANGING");
        case WM_PALETTECHANGED:     return("WM_PALETTECHANGED");
        case WM_HOTKEY:             return("WM_HOTKEY");
        case WM_PRINT:              return("WM_PRINT");
        case WM_PRINTCLIENT:        return("WM_PRINTCLIENT");
        case WM_USER:               return("WM_USER");
        case WM_USER+1:             return("WM_USER+1");
        case WM_USER+2:             return("WM_USER+2");
        case WM_USER+3:             return("WM_USER+3");
        case WM_USER+4:             return("WM_USER+4");
    }

    return("");
}